package com.example.order.config;

import static com.example.common.constant.Constant.ResourceServerId.*;

import com.example.common.constant.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.annotation.Resource;

/**
 * 配置本服务为资源服务器
 *
 * @auth 罗俊华
 * @Date 2022/3/10 10:13 下午
 */
@Slf4j
@Configuration
@EnableResourceServer
/**
 *
 * 让资源服务器的注解生效@PreAuthorize
 * 因为 @EnableWebSecurity 注解继承了 @EnableGlobalMethodSecurity，所以单独只使用@EnableWebSecurity注解也能使得@PreAuthorize注解生效
 */
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {



    @Resource
    private TokenStore tokenStore;

    /**
     * 相当于手动发送校验令牌的请求：
     * localhost:8801/oauth/check_token?client_id=luo&client_secret=1234&token=5c9a512f-7b50-4a36-add0-98e8569a01e5
     * @return
     */
    @Bean
    public ResourceServerTokenServices resourceServerTokenServices(){


        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();

        /**
         * 使用远程服务调用，请求授权服务器（authorization server）来校验 token
         * 校验时，必须指定认证服务器的 url，client_id，client_secret
         * 前提是：authorization server 开放了 token 校验接口
         * security.checkTokenAccess("permitAll()")
         * */
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:8801/oauth/check_token");

        remoteTokenServices.setClientId(/*Constant.ResourceServiceAccount.CLIENT_ID*/"luo");

        remoteTokenServices.setClientSecret(/*Constant.ResourceServiceAccount.CLIENT_SECRET*/"1234");

        return remoteTokenServices;
    }


    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {

//        本资源服务器的id
        resources.resourceId(ORDER_SERVICE)
//                调用远程auth service 来验证令牌是否有效的服务
//                .tokenServices(resourceServerTokenServices())

//                调用本地的 tokenStore 对象来验证 用户的token是否有效
                .tokenStore(tokenStore)
                .stateless(true);

    }


    @Override
    public void configure(HttpSecurity http) throws Exception {

        http
                .authorizeRequests()
                .antMatchers("/**")
                // authorization server 中的 第三方 client 所拥有的 scope
                .access("#oauth2.hasAnyScope('add')")
                .and()
                .csrf()
                .disable()
                .sessionManagement()
                /**
                 * 因为所有的一切都是基于 token 进行认证的，所以就可以把 session 给彻底关闭了
                 * */
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);


    }
}
